package com.example.model;

import com.alibaba.fastjson.JSONObject;
import com.example.annotations.Param;
import com.example.freemarker.FreemarkerConfig;
import com.example.handler.HttpHandler;

import com.example.utils.ObjectMaps;
import com.example.utils.ObjectTypeUtils;
import com.example.utils.StringUtils;
import freemarker.template.Configuration;
import freemarker.template.Template;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RequestBody;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.multipart.MultipartForm;

import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @Classname HttpTemplateBody
 * @Description TODO
 * @Date 2022/5/29 0:08
 * @Created by XiongXiong
 * @Author: X.I.O
 */
public class HttpTemplateBody {

  private HttpHandler httpHandler;

  private Configuration configuration;

  public Handler<RoutingContext> body(Method method, Object obj, Class<?>[] clazzs){
    return routingContext -> {
      Object objStr=null;
      try {

        List<Object> objList=new ArrayList<Object>();
        MultiMap multiMap=routingContext.queryParams();


        MultipartForm multipartForm = MultipartForm.create();
        MultiMap attributes = routingContext.request()
          .formAttributes();

        attributes.forEach(attribute -> {
          multipartForm.attribute(attribute.getKey(), attribute.getValue());
        });

        Map map = new HashMap();
        if(clazzs.length>0){
          for (int i = 0; i < clazzs.length; i++) {
            Class<?> cls=clazzs[i];
            Annotation[][] annotations= method.getParameterAnnotations();
            Annotation[] an=annotations[i];
            if(cls.getName().equals(HttpServerResponse.class.getName())){
              objList.add(routingContext.response());
            }else if(cls.getName().equals(HttpServerRequest.class.getName())) {
              HttpServerRequest request = routingContext.request();
              objList.add(request);
            }else if("java.util.HashMap".equals(cls.getName()) || "java.util.Map".equals(cls.getName())) {
                objList.add(map);
            }else if (an.length>0) {
              //处理注解
              dealAnnationParamHandler(objList,an,cls,routingContext,multiMap);
            }else if(cls.getName().equals(UploadModel.class.getName())){

              objList.add(null);
            }else {
              objList.add(null);
            }
          }
          if(httpHandler==null){
            Object httpHandlerObj= ObjectMaps.getObjectByClass(HttpHandler.class);
            if(httpHandlerObj != null){
              httpHandler=(HttpHandler)httpHandlerObj;
            }
          }
          if(httpHandler!=null){
            httpHandler.bedoreHandler(objList.toArray());
          }
          objStr=method.invoke(obj,objList.toArray());

          if(httpHandler!=null){
            Object value=httpHandler.afterHandler(objList.toArray(),objStr);
            if(value != null){
              objStr=value;
            }
          }
        }else {
          objStr=method.invoke(obj);
        }
       if(configuration==null){
          FreemarkerConfig config=(FreemarkerConfig) ObjectMaps.getObjectByClass(FreemarkerConfig.class);
          if(config!=null){
              configuration=config.getFreemarkerConfig();
          }
       }
       if(configuration!=null){
           Template template = configuration.getTemplate(String.valueOf(objStr));
           StringWriter stringWriter = new StringWriter();
           template.process(map, stringWriter);
           objStr = stringWriter.toString();
       }
      }catch (Exception e) {
        e.printStackTrace();
      }
      routingContext.response()
        .end(String.valueOf(objStr));
    };
  }

  //处理注解
  private void dealAnnationParamHandler(List<Object> objList, Annotation[] an,Class<?> cls,RoutingContext routingContext,MultiMap multiMap){
    Param param = paramFieldHandler(an);
    if (multiMap == null) {
      routingContext.response().putHeader("content-type", "application/json; charset=utf-8").end("参数不得为空");
    }
    if(param!=null){
      if (multiMap != null) {
        //默认值
        String defaultValue=param.defalultValue();
        Object value = multiMap.get(param.value());
        //value非空并且开启了 required注解
        if (StringUtils.isEmpty(value) ) {
          RequestBody req=routingContext.body();
          JsonObject var=req.asJsonObject();

          if(var!=null && ! var.isEmpty()){
            Map o=var.getMap();
            Object v=o.get(param.value());
            //获取到的值为空，赋值默认值
            if(v==null && !"".equals(defaultValue)){
              v=defaultValue;
            }
            if(v==null && param.required()){
              routingContext.response().putHeader("content-type", "application/json; charset=utf-8").end(param.value() + "不得为空");
              return;
            }
            paramTypeChange(v,cls,objList);
          }else {
            if(value==null && !"".equals(defaultValue)){
              value=defaultValue;
              paramTypeChange(value,cls,objList);
            }else if(param.required()) {
              routingContext.response().putHeader("content-type", "application/json; charset=utf-8").end(param.value() + "不得为空");
              return;
            }else {
              objList.add(null);
            }
          }
        }else if( !param.required() && StringUtils.isEmpty(value)){
          //获取到的值为空，赋值默认值
          objList.add(null);
        }else  {
          //参数类型处理
          paramTypeChange(value,cls,objList);
        }
      }
    }
  }

  private Param paramFieldHandler(Annotation[] annotations){
    for (int i = 0; i < annotations.length; i++) {
      Annotation annotation = annotations[i];
      if(annotation instanceof Param){
        Param param = (Param) annotation;
        return param;
      }
    }
    return null;
  }

  //参数类型改变
  private void paramTypeChange(Object obj,Class<?> cls,List<Object> objectList){
    if(obj==null){
      objectList.add(null);
    }else if("java.lang.Integer".equals(cls.getName())){
      Integer value= ObjectTypeUtils.getInteger(String.valueOf(obj));
      objectList.add(value);
    }else if ("java.lang.Double".equals(cls.getName())) {
      Double value = ObjectTypeUtils.getDouble(String.valueOf(obj));
      objectList.add(value);
    }else if("java.lang.Float".equals(cls.getName())){
      Float value = ObjectTypeUtils.getFloat(String.valueOf(obj));
      objectList.add(value);
    }else if("java.util.Date".equals(cls.getName())){
      Date date = ObjectTypeUtils.getDate(String.valueOf(obj));
      objectList.add(date);
    }else  {
      String str=JSONObject.toJSONString(obj);
      Object v=JSONObject.parseObject(str,cls);
      objectList.add(v);
    }
  }


}
